package com.zealfi.example.test.rabbitmq.config;

import com.zealfi.example.test.rabbitmq.constant.ExchangeEnum;
import com.zealfi.example.test.rabbitmq.util.JsonTool;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;


/**
 * @功能:【RabbitMQConfig RabbitMQ配置】
 * @作者:代守诚
 * @日期:2018/10/19
 * @时间:9:38
 */
@Configuration
public class RabbitmqConfig {

    /**
     * 服务器主机地址
     */
    @Value("${spring.rabbitmq.config.host}")
    private String host;
    /**
     * 端口
     */
    @Value("${spring.rabbitmq.config.port}")
    private Integer port;
    /**
     * 用户名
     */
    @Value("${spring.rabbitmq.config.username}")
    private String username;
    /**
     * 密码
     */
    @Value("${spring.rabbitmq.config.password}")
    private String password;
    /**
     * 虚拟机地址
     */
    @Value("${spring.rabbitmq.config.virtualHost}")
    private String virtualHost;

    /**
     * 连接器
     */
    @Bean
    public ConnectionFactory createConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        /**
         * 同样一个RabbitTemplate只支持一个ConfirmCallback。
         * 对于发布确认，template要求CachingConnectionFactory的publisherConfirms属性设置为true。
         * 如果客户端通过setConfirmCallback(ConfirmCallback callback)注册了RabbitTemplate.ConfirmCallback，那么确认消息将被发送到客户端。
         * 这个回调函数必须实现以下方法：
         * void confirm(CorrelationData correlationData, booleanack);
         */
        connectionFactory.setPublisherConfirms(true);//开启confirm模式
        /**
         * 对于每一个RabbitTemplate只支持一个ReturnCallback。
         * 对于返回消息，模板的mandatory属性必须被设定为true，
         * 它同样要求CachingConnectionFactory的publisherReturns属性被设定为true。
         * 如果客户端通过调用setReturnCallback(ReturnCallback callback)注册了RabbitTemplate.ReturnCallback，那么返回将被发送到客户端。
         * 这个回调函数必须实现下列方法：
         *void returnedMessage(Message message, intreplyCode, String replyText,String exchange, String routingKey);
         */
        connectionFactory.setPublisherReturns(true);
        System.out.println("创建消息ConnectionFactory" + username);
        return connectionFactory;
    }

    /***
     *  消息操作模板 这里写成多例，是为了后续 针对特定业务定义特定的回调
     * @return
     */
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //每次注入的时候回自动创建一个新的bean实例
    public RabbitTemplate amqpTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(createConnectionFactory());
        rabbitTemplate.setExchange(ExchangeEnum.BD_FENQI_EXCHANGE.getValue());
        System.out.println("*************" + JsonTool.getJsonString(rabbitTemplate));
        return rabbitTemplate;
    }

    /**
     * queue listener  观察 监听模式
     * 当有消息到达时会通知监听在对应的队列上的监听对象
     *
     * @return
     */
    public SimpleMessageListenerContainer getSimpleMessageListenerContainer(ChannelAwareMessageListener mqConsumer) {
        System.err.println("#############进入监听者#############");
        SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(createConnectionFactory());
        listenerContainer.setExposeListenerChannel(true);//暴露监听渠道
        listenerContainer.setMaxConcurrentConsumers(10); //最大消费者数，大于ConcurrentConsumers
        listenerContainer.setConcurrentConsumers(3); //消费者数量
        listenerContainer.setAcknowledgeMode(AcknowledgeMode.MANUAL); //设置确认模式手工确认
        listenerContainer.setMessageListener(mqConsumer);//监听的消费者
        return listenerContainer;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getVirtualHost() {
        return virtualHost;
    }

    public void setVirtualHost(String virtualHost) {
        this.virtualHost = virtualHost;
    }
}
